#ifndef MODEL_CC
#define MODEL_CC
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<iterator>
#include<vector>
#include<map>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include "def.hpp"
#include "io.hpp"
#include "log.hpp"
#include "utils.hpp"
#include "topicmodel.hpp"
#include "topicmodel_getmodel.hpp"

using namespace std;

int TopicModel(){
  GenericTopicModel* topic_model = getTopicModel();
  if(PuzaDEF::Instance()->currentTopicModelTaskType == TOPICMODEL_TASK_INFERENCE){
    int ProcessedDOCS = 0;
    while(1){
      int remain = topic_model->GetDocuments(0);
      if(topic_model->TM_DOCS.size()!=0){
	  PuzaLogger::Instance()->PutString("Read " +  to_string<int>(topic_model->TM_DOCS.size(),std::dec) + " Documents.");
	  topic_model->Inference();
	  ProcessedDOCS += topic_model->TM_DOCS.size();
	  PuzaLogger::Instance()->PutString("Totally Processed " +  to_string<int>(ProcessedDOCS,std::dec) + " Documents.");
      }
      if(remain == 0)
	break;
    }
    topic_model->SaveModel();
  }
  else if(PuzaDEF::Instance()->currentTopicModelTaskType == TOPICMODEL_TASK_INFERENCE_AND_PREDICTION){
    // we first do inference
    PuzaLogger::Instance()->PutString("============= Training Phase ================");
    int ProcessedDOCS = 0;
    PuzaDEF::Instance()->input_file_name = PuzaDEF::Instance()->train_file_name;
    while(1){
      int remain = topic_model->GetDocuments(0);
      if(topic_model->TM_DOCS.size()!=0){
	PuzaLogger::Instance()->PutString("Read " +  to_string<int>(topic_model->TM_DOCS.size(),std::dec) + " Documents.");
	topic_model->Inference();
	ProcessedDOCS += topic_model->TM_DOCS.size();
	PuzaLogger::Instance()->PutString("Totally Processed " +  to_string<int>(ProcessedDOCS,std::dec) + " Documents.");
      }
      if(remain == 0)
        break;
    }
    topic_model->SaveModel();
    // we then do prediction
    // readjust to online model
    PuzaLogger::Instance()->PutString("============= Testing Phase ================");
    ProcessedDOCS = 0;
    PuzaDEF::Instance()->input_file_name = PuzaDEF::Instance()->test_file_name;
    topic_model->GetDocuments(1);
    if(topic_model->TM_DOCS.size()!=0){
      PuzaLogger::Instance()->PutString("Read " +  to_string<int>(topic_model->TM_DOCS.size(),std::dec) + " Documents.");
      topic_model->Prediction();
      ProcessedDOCS += topic_model->TM_DOCS.size();  
      PuzaLogger::Instance()->PutString("Totally Processed " +  to_string<int>(ProcessedDOCS,std::dec) + " Documents.");
    }
  }
  else if(PuzaDEF::Instance()->currentTopicModelTaskType == TOPICMODEL_TASK_INTERACTIVE){
    PuzaLogger::Instance()->PutString("============= Interactive Trainig and Testing ================");
    int ProcessedDOCS = 0;
    PuzaDEF::Instance()->input_file_name = PuzaDEF::Instance()->train_file_name;
    topic_model->GetDocuments(0);
    PuzaDEF::Instance()->input_file_name = PuzaDEF::Instance()->test_file_name;
    if(topic_model->TM_DOCS.size()!=0){
      PuzaLogger::Instance()->PutString("Read " +  to_string<int>(topic_model->TM_DOCS.size(),std::dec) + " Documents.");
      ProcessedDOCS += topic_model->TM_DOCS.size();
      PuzaLogger::Instance()->PutString("Totally Processed " +  to_string<int>(ProcessedDOCS,std::dec) + " Documents.");
      topic_model->Interactive();
    }
    topic_model->SaveModel();
  }
  delete topic_model;
  return 0;
}

#endif
